using System;
using System.Collections.Generic;
using System.Text;
using System.Drawing;

namespace Genetic_Tetris
{
    public class MoveDecider
    {
        public MoveDecider()
        {

        }


        public Move DecideMove(Board currentBoard, Piece pieceIn, HeuristicConstants heuristic)
        {
            //from the current board, given the current piece,
            //find all possible resulting boards

            List<Move> moveList = new List<Move>();


            //handle rotational symetry
            int rotationsNeeded = -1;
            if (pieceIn.Type == Piece.PieceType.I)
            {
                rotationsNeeded = 2;
            }
            else if (pieceIn.Type == Piece.PieceType.O)
            {
                rotationsNeeded = 1;
            }
            else if (pieceIn.Type == Piece.PieceType.S)
            {
                rotationsNeeded = 2;
            }
            else if (pieceIn.Type == Piece.PieceType.Z)
            {
                rotationsNeeded = 2;
            }
            else
            {
                //J, L, and T all need 4
                rotationsNeeded = 4;
            }

            for (int i = 0; i < rotationsNeeded; i++)
            {
                pieceIn.RotateLeft();
                for (int x = 0; x < currentBoard.WIDTH; x++)
                {
                    if (currentBoard.IsValidMove(pieceIn, x))
                    {
                        Move tempMove = new Move();

                        Piece tempPiece = new Piece();
                        tempPiece.Blocks = (Point[])pieceIn.Blocks.Clone();
                        tempPiece.Rotation = pieceIn.Rotation;
                        tempPiece.Type = pieceIn.Type;
                        tempMove.Piece = tempPiece;

                        tempMove.Column = x;

                        Board tempBoard = new Board();
                        tempBoard.Grid = (bool[,])currentBoard.Grid.Clone();

                        tempBoard.PlacePieceInColumn(tempPiece, x);

                        tempMove.ResultingBoard = tempBoard;
                        moveList.Add(tempMove);
                    }


                }
            }

            for (int i = 0; i < moveList.Count; i++)
            {
                moveList[i].Fitness = Evaluate(moveList[i].ResultingBoard, heuristic);
            }
            moveList.Sort();

            Move moveToMake = null;
            if (moveList.Count > 0)
            {
                moveToMake = moveList[0];
            }


            return moveToMake;
        }

        //Heuristic Evaluation
        public double Evaluate(Board boardIn, HeuristicConstants heuristicIn)
        {
            double fitness = 0;

            //Rows completed
            int completeRows = boardIn.GetCompleteRowCount();

            boardIn.ProcessCompleteRows();

            //Max Block Height
            int maxHeight = boardIn.GetMaxHeight();
            
            //Gap Count
            int gapCount = boardIn.GetGapCount();

            //holes per row
            double WeightedBlocksPerRow = boardIn.GetWeightedBlocksPerRow();

            
            double averageHeight = boardIn.GetAverageHeight();
            int alternations = boardIn.GetAlternations();

            int burialDepth = boardIn.GetBurialDepth();

            //add up raw scores modified by heuristic values
            fitness += (maxHeight * heuristicIn.Constants["MaxBlockHeight"]);
            fitness += (completeRows * heuristicIn.Constants["RowsCompleted"]);
            fitness += (gapCount * heuristicIn.Constants["GapCount"]);
            fitness += (WeightedBlocksPerRow * heuristicIn.Constants["WeightedBlocksPerRow"]);
            fitness += (averageHeight * heuristicIn.Constants["AverageHeight"]);
            fitness += (alternations * heuristicIn.Constants["Alternations"]);
            fitness += (burialDepth * heuristicIn.Constants["BurialDepth"]);
            return fitness;
        }

        






    }
}
